package com.android.powerbankpad.posutils;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbManager;
import android.text.TextUtils;

import com.android.powerbankpad.api.ApiUrl;
import com.android.powerbankpad.bean.PosOrderBean;
import com.android.powerbankpad.config.Constants;
import com.android.powerbankpad.network.CommonalityModel;
import com.android.powerbankpad.network.NetWorkListener;
import com.android.powerbankpad.network.okHttpModel;
import com.pax.poscomm.usb.utils.USBUtil;
import com.pax.poscore.LogSetting;
import com.pax.poscore.commsetting.UartSetting;
import com.pax.poscore.commsetting.UsbSetting;
import com.pax.poslinkupt.ExecutionResult;
import com.pax.poslinkupt.POSLinkUPT;
import com.pax.poslinkupt.Terminal;
import com.pax.poslinkupt.admin.ResetRsp;
import com.pax.poslinkupt.admin.SetConfigurationReq;
import com.pax.poslinkupt.admin.SetConfigurationRsp;
import com.pax.poslinkupt.report.GetCardInfoReq;
import com.pax.poslinkupt.report.GetCardStatusRsp;
import com.pax.poslinkupt.transaction.TransactionCompletionReq;
import com.pax.poslinkupt.transaction.TransactionCompletionRsp;
import com.pax.poslinkupt.transaction.TransactionReversalReq;
import com.pax.poslinkupt.transaction.TransactionReversalRsp;
import com.pax.poslinkupt.transaction.TransactionStartReq;
import com.pax.poslinkupt.transaction.TransactionStartRsp;
import com.pax.poslinkupt.util.SConfigurationInfo;
import com.ws.universal.tools.eventbus.BaseBusData;
import com.ws.universal.tools.eventbus.EventBusUtil;
import com.ws.universal.tools.utils.CacheUtils;
import com.ws.universal.tools.utils.GsonUtils;
import com.ws.universal.tools.utils.LogcatUtils;
import com.ws.universal.tools.utils.StringUtils;
import com.ws.universal.tools.utils.ThreadUtils;
import com.ws.universal.tools.utils.TimeDateUtils;
import com.ws.universal.tools.utils.ToastUtils;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;

public class PosSerialPort implements NetWorkListener {
    public boolean isPosDevice = false;

    private final String ACTION_USB_PERMISSION = "com.pax.poslink.USB_PERMISSION";//可自定义
    public Terminal terminal;
    public String account;//账户，卡号
    private String amount;//金额

    private List<SConfigurationInfo> configurations;
    private SConfigurationInfo sConfigurationInfo;
    private SetConfigurationReq setConfigurationReq;
    private boolean isReadCard = false;//是否读到卡
    //正在刷卡支付
    private boolean isHavePos = false;//是否有pos机
    private PosListener posListener;
    private Activity activity;
    private UsbSetting usbSetting;
    private UsbSetting readCardUsbSetting;

    private UartSetting uartSetting;
    private UartSetting readCardUartSetting;
    public boolean isSerialPort;
    private UsbManager mUsbManager;

    private PendingIntent mPermissionIntent;

    /*private String baifu_order_no;
    private String baifu_originalHostData;
    private String baifu_originalHostReferenceNumber;*/

    private int paySize = 0;//要支付的订单列表长度
    private int currentPayIndex = 0;//当前支付的订单列表下标
    public boolean loopCheckoutOrder = true;
    private PosOrderBean posOrderBean;

    public void setPosListener(PosListener posListener) {
        this.posListener = posListener;
    }

    public void setActivity(Activity activity) {
        this.activity = activity;
    }

    public boolean isHavePos() {
        return isHavePos;
    }

    private void setHavePos(boolean havePos) {
        isHavePos = havePos;
    }


    public void initPosUsbParams(String amount) {
        LogcatUtils.e("pos机 initPosUsbParams");
        LogSetting logSetting = new LogSetting();
        logSetting.setEnable(true);
        logSetting.setLevel(LogSetting.LogLevel.DEBUG);
        logSetting.setDays(30);
        logSetting.setFileName("POSLog");

        usbSetting = new UsbSetting();
        usbSetting.setTimeout(60000);


        readCardUsbSetting = new UsbSetting();
        readCardUsbSetting.setTimeout(2000);


        GetCardInfoReq.builder().timeout("6000").build();
        //配置刷卡金额
        sConfigurationInfo = new SConfigurationInfo();
        sConfigurationInfo.setName("preprocessingAmount");
        this.amount = amount;
        sConfigurationInfo.setValue(amount);
        if (configurations == null) {
            configurations = new ArrayList<>();
        }
        configurations.add(sConfigurationInfo);
        initSetConfig(false);

        loopCheckoutOrder();
    }

    public void initPosSerialParams(String amount) {

        LogcatUtils.e("pos机 initPosSerialParams");
        LogSetting logSetting = new LogSetting();
        logSetting.setEnable(true);
        logSetting.setLevel(LogSetting.LogLevel.DEBUG);
        logSetting.setDays(30);
        logSetting.setFileName("POSLog");

        POSLinkUPT.getInstance().setLogSetting(logSetting);
        uartSetting = new UartSetting();
        uartSetting.setTimeout(60000);
        uartSetting.setBaudRate("115200");
        uartSetting.setSerialPort("/dev/ttyS0");

        readCardUartSetting = new UartSetting();
        readCardUartSetting.setTimeout(2000);
        readCardUartSetting.setBaudRate("115200");
        readCardUartSetting.setSerialPort("/dev/ttyS0");


        //配置刷卡金额
        sConfigurationInfo = new SConfigurationInfo();
        sConfigurationInfo.setName("preprocessingAmount");
        this.amount = amount;
        sConfigurationInfo.setValue(amount);
        if (configurations == null) {
            configurations = new ArrayList<>();
        }
        configurations.add(sConfigurationInfo);
        initSetConfig(true);

        loopCheckoutOrder();
    }


    private void loopCheckoutOrder() {
        //如果用户还到了 没有POS机的设备 由当前带了pos机的设备进行扣款
        Observable.interval(60, TimeUnit.SECONDS) // 每隔60秒发射一个递增的长整数
                .subscribe(aLong -> {

                    // 在这里执行您希望循环执行的操作 loopCheckoutOrder 是否循环
                    if (loopCheckoutOrder) {
                        LogcatUtils.e("每隔60秒执行一次 checkoutOrder ");
                        checkoutOrder();
                    }


                });
    }

    public void initSetConfig(boolean isSerialPort) {
        this.isSerialPort = isSerialPort;
        new Thread(new Runnable() {
            @Override
            public void run() {
                LogcatUtils.e("pos机 执行初始化 9");
                if (isSerialPort) {
                    terminal = POSLinkUPT.getInstance().getTerminal(activity, uartSetting);
                } else {
                    terminal = POSLinkUPT.getInstance().getTerminal(activity, usbSetting);
                }
                setConfigurationReq = new SetConfigurationReq.Builder().configurations(configurations).build();
                ExecutionResult<SetConfigurationRsp> executionResult = terminal.getAdmin().setConfiguration(setConfigurationReq);
                LogcatUtils.e("pos机 executionResult result " + executionResult.isSuccessful() + " msg " + executionResult.message());
                if (executionResult.isSuccessful()) {
                    BaseBusData beautyDate = new BaseBusData(Constants.baifu_pos_init);
                    EventBusUtil.postEvent(beautyDate);
                    //初始化监听
                    account = "";
                    //监听刷卡
                    ThreadUtils.executeBySingleAtFixRate(taskRead, 2, TimeUnit.SECONDS);
                } else {
                    if (posListener != null) {
                        posListener.initFail();
                    }

                }


            }
        }).start();

    }

    private ThreadUtils.Task taskRead = new ThreadUtils.Task() {
        @Override
        public Object doInBackground() throws Throwable {
            swipeListener();
            return null;
        }

        @Override
        public void onSuccess(Object result) {

        }

        @Override
        public void onCancel() {

        }

        @Override
        public void onFail(Throwable t) {

        }
    };


    public void cancelCardInfo() {
        new Thread(() -> {
            account = "";
            ExecutionResult<ResetRsp> result = terminal.getAdmin().reset();
            LogcatUtils.e("pos机 执行清空卡信息  terminal msg " + result.message() + " isSuccessful " + result.isSuccessful());
            if (result.isSuccessful()) {
                LogcatUtils.e("pos机 执行清空卡信息  result.isSuccessful() true 继续读卡 ");
                isReadCard = false;
            } else {
                LogcatUtils.e("pos机 执行清空卡信息  失败 停止读卡  ");
                cancelCardInfo();
            }

        }).start();

    }

    //轮询监听刷卡
    public void swipeListener() {
        //LogcatUtils.e("pos机 监听刷卡  swipeListener ");
        try {
            if (!isReadCard) {
                Terminal terminal1 = null;
                if (isSerialPort) {
                    terminal1 = POSLinkUPT.getInstance().getTerminal(activity, readCardUartSetting);
                } else {
                    terminal1 = POSLinkUPT.getInstance().getTerminal(activity, readCardUsbSetting);
                }

                ExecutionResult<GetCardStatusRsp> result = terminal1.getReport().getCardStatus();
                if (result.isSuccessful()) {
                    if (!TextUtils.isEmpty(result.response().account())) {
                        isReadCard = true;
                        account = result.response().account();
                        LogcatUtils.e("pos机 监听刷卡  account " + account + " getCurrentDate GetCardStatusRsp " + TimeDateUtils.getCurrentDate("yyyy年M月d日 HH:mm：ss", TimeDateUtils.getTimeStamp()));
                        onDeviceScan();
                    } else {
                        LogcatUtils.e("pos机 监听刷卡  没刷卡 else " + TimeDateUtils.getCurrentDate("yyyy年M月d日 HH:mm：ss", TimeDateUtils.getTimeStamp()));
                    }
                }
                LogcatUtils.e(" pos机 isSuccessful " + result.isSuccessful() + " msg " + result.message() + " code " + result.code());
            }
        } catch (Exception e) {
            LogcatUtils.e("pos机 监听刷卡  报错 e " + e.getMessage().toString());
        }
    }


    //获取USB权限
    @SuppressLint("UnspecifiedImmutableFlag")
    public void getUsbPermission(String amount) {
        mPermissionIntent = PendingIntent.getBroadcast(activity, 0, new Intent(ACTION_USB_PERMISSION), 0);
        mUsbManager = (UsbManager) activity.getSystemService(Context.USB_SERVICE);

        //LogcatUtils.e("pos机 USBUtil getUsbPermission " + USBUtil.getDevice(activity).getVendorId() + " getProductId " + USBUtil.getDevice(activity).getProductId() + USBUtil.getDevice(activity).getDeviceName());

        if (USBUtil.getDevice(activity) != null) {
            if (mUsbManager.hasPermission(USBUtil.getDevice(activity))) {
                LogcatUtils.e("pos机 getUsbPermission 已获取过USB权限 getUsbPermission " + USBUtil.getDevice(activity).getVendorId() + " getProductId " + USBUtil.getDevice(activity).getProductId() + USBUtil.getDevice(activity).getDeviceName());
                setHavePos(true);
                initPosUsbParams(amount);
            } else {
                LogcatUtils.e("pos机 请求获取USB权限 getUsbPermission " + USBUtil.getDevice(activity).getVendorId() + " getProductId " + USBUtil.getDevice(activity).getProductId() + USBUtil.getDevice(activity).getDeviceName());
                mUsbManager.requestPermission(USBUtil.getDevice(activity), mPermissionIntent);
                getUsbPermission(amount);
            }
        } else {
            LogcatUtils.e("pos机 无Usb设备,请插入pos机");
            setHavePos(false);
        }

    }

    //获取USB权限
    @SuppressLint("UnspecifiedImmutableFlag")
    public void initPermission() {

        mPermissionIntent = PendingIntent.getBroadcast(activity, 0, new Intent(ACTION_USB_PERMISSION), 0);
        mUsbManager = (UsbManager) activity.getSystemService(Context.USB_SERVICE);
        LogcatUtils.e("pos机 请求获取USB权限 getDevice is null " + USBUtil.getDevice(activity) == null ? true : false);

        if (USBUtil.getDevice(activity) != null) {

            if (mUsbManager.hasPermission(USBUtil.getDevice(activity))) {
                LogcatUtils.e("pos机 已获取过USB权限 initPermission " + USBUtil.getDevice(activity).getVendorId() + " getProductId " + USBUtil.getDevice(activity).getProductId() + USBUtil.getDevice(activity).getDeviceName());
                setHavePos(true);
            } else {
                LogcatUtils.e("pos机 请求获取USB权限 initPermission " + USBUtil.getDevice(activity).getVendorId() + " getProductId " + USBUtil.getDevice(activity).getProductId() + USBUtil.getDevice(activity).getDeviceName());
                mUsbManager.requestPermission(USBUtil.getDevice(activity), mPermissionIntent);
            }

        } else {
            LogcatUtils.e("pos机 无Usb设备,请插入pos机");
            setHavePos(false);
        }

    }


    //Step 1 读卡
    private void onDeviceScan() {


        if (posListener != null) {
            posListener.readCard();
        }

        String baseUrl = CacheUtils.getString(Constants.base_url) + "/app/baifu/deviceScan";
        Map<String, String> params = new HashMap<>();
        params.put("sn", CacheUtils.getString(Constants.serial_number));
        okHttpModel.post(baseUrl, params, ApiUrl.baifu_deviceScan_Id, this);
    }

    //Step 2 创建订单
    private void createOrder(String card_no) {
        String baseUrl = CacheUtils.getString(Constants.base_url) + "/app/baifu/createOrder";
        Map<String, String> params = new HashMap<>();
        params.put("sn", CacheUtils.getString(Constants.serial_number));
        params.put("card_no", card_no);
        okHttpModel.post(baseUrl, params, ApiUrl.baifu_createOrder_Id, this);


    }

    //Step 3 预付款
    public void transactionStar(String account, String order_no) {
        new Thread(() -> {

            TransactionStartReq transactionStartReq = TransactionStartReq.builder().account(account).
                    transactionAmount(amount).registerReferenceNumber(order_no).build();
            ExecutionResult<TransactionStartRsp> transactionStart = terminal.getTransaction().start(transactionStartReq);
            if (transactionStart.isSuccessful()) {
                TransactionStartRsp response = transactionStart.response();


                if (response != null) {
                    LogcatUtils.e("pos机 执行预授权扣款 transactionStar account " + account + " getCurrentDate TransactionStartReq " +
                            TimeDateUtils.getCurrentDate("yyyy年M月d日 HH:mm：ss", TimeDateUtils.getTimeStamp()) +
                            " hostData " + response.hostData() + " hostReferenceNumber " + response.hostReferenceNumber() +
                            " msg " + response.responseMessage() + " responseCode " + response.responseCode());
                    if (!StringUtils.isEmpty(response.hostData()) && !StringUtils.isEmpty(response.hostReferenceNumber())) {
                        transactionStarSuccess(order_no, response.hostData(), response.hostReferenceNumber());
                    } else {
                        cancelCardInfo();
                        if (posListener != null) {
                            posListener.freezeFail();
                        }
                        LogcatUtils.e(" pos机 执行预授权扣款失败 " + transactionStart.response().responseCode());
                        ToastUtils.showShort("预授权扣款失败 " + transactionStart.response().responseCode(), 5000);

                    }
                } else {
                    cancelCardInfo();
                    if (posListener != null) {
                        posListener.freezeFail();
                    }
                    LogcatUtils.e(" pos机 执行预授权扣款失败 " + transactionStart.isSuccessful());
                    ToastUtils.showShort("预授权扣款失败 " + transactionStart.isSuccessful(), 5000);

                }

            } else {
                cancelCardInfo();
                if (posListener != null) {
                    posListener.freezeFail();
                }
                LogcatUtils.e(" pos机 执行预扣款回调 执行预授权扣款失败 " + transactionStart.isSuccessful());
                ToastUtils.showShort("预授权扣款失败 " + transactionStart.isSuccessful(), 5000);

            }
        }).start();

    }

    //Step 4 预授权扣款成功
    private void transactionStarSuccess(String order_no, String originalHostData, String originalHostReferenceNumber) {
        String baseUrl = CacheUtils.getString(Constants.base_url) + "/app/baifu/freezeSuccess";
        Map<String, String> params = new HashMap<>();
        params.put("order_no", order_no);
        params.put("originalHostData", originalHostData);
        params.put("originalHostReferenceNumber", originalHostReferenceNumber);
        okHttpModel.post(baseUrl, params, ApiUrl.baifu_freezeSuccess_Id, this);


    }

    //Step 5 撤销预授权扣款
    /*private void cancelFreeze(String card_no) {
        String baseUrl = CacheUtils.getString(Constants.base_url) + "/app/baifu/cancelFreeze";
        Map<String, String> params = new HashMap<>();
        params.put("card_no", card_no);
        okHttpModel.post(baseUrl, params, ApiUrl.baifu_cancelFreeze_Id, this);
    }*/


    //Step 6 检查待支付订单
    public void checkoutOrder() {
        String baseUrl = CacheUtils.getString(Constants.base_url) + "/app/baifu/checkoutOrder";
        okHttpModel.post(baseUrl, null, ApiUrl.baifu_checkoutOrder_Id, this);

    }

    //Step 7 实际扣款成功 告知服务器
    private void payOrderSuccess(String order_no) {
        String baseUrl = CacheUtils.getString(Constants.base_url) + "/app/baifu/payOrderSuccess";
        Map<String, String> params = new HashMap<>();
        params.put("order_no", order_no);
        okHttpModel.post(baseUrl, params, ApiUrl.baifu_payOrderSuccess_Id, this);

    }


    //预授权失败时 撤销预授权扣款 最终交易失败时 也需要撤销预授权
    public void cancelTransactionReversal(String originalHostData, String originalHostReferenceNumber) {
        TransactionReversalReq req = TransactionReversalReq.builder().originalHostData(originalHostData).originalHostReferenceNumber(originalHostReferenceNumber).build();
        new Thread(() -> {
            ExecutionResult<TransactionReversalRsp> result = terminal.getTransaction().reversal(req);
            if (result.isSuccessful()) {
                LogcatUtils.e(" pos机 执行 撤销交易成功 ");
                ToastUtils.showShort("撤销交易成功", 5000);
            } else {
                LogcatUtils.e(" pos机 执行撤销交易失败 ");
                ToastUtils.showShort("撤销交易失败", 5000);
            }
        }).start();

    }


    //最终交易 扣款
    public void TransactionCompletion(String amount, String order_no, String originalHostData, String originalHostReferenceNumber) {

        new Thread(() -> {
            LogcatUtils.e("pos机 order_no " + order_no + " TransactionCompletion params originalHostData " + originalHostData + " originalHostReferenceNumber " + originalHostReferenceNumber);
            TransactionCompletionReq req = TransactionCompletionReq.builder().transactionAmount(amount).originalHostData(originalHostData).originalHostReferenceNumber(originalHostReferenceNumber).build();
            if (terminal != null) {
                ExecutionResult<TransactionCompletionRsp> transactionCompletionRsp = terminal.getTransaction().complete(req);
                if (transactionCompletionRsp != null) {
                    if (transactionCompletionRsp.isSuccessful()) {
                        TransactionCompletionRsp response = transactionCompletionRsp.response();
                        if (response != null) {
                            LogcatUtils.e(" pos机 TransactionCompletion transactionCompletionRsp is isSuccessful ");
                            payOrderSuccess(order_no);
                        }
                    } else {
                        LogcatUtils.e(" pos机 TransactionCompletion isFail ");
                        ToastUtils.showShort(" pos机 TransactionCompletion isFail ");
                    }
                } else {
                    LogcatUtils.e(" pos机 TransactionCompletion transactionCompletionRsp is null ");
                    ToastUtils.showShort(" pos机 TransactionCompletion transactionCompletionRsp is null  ");
                }

            } else {
                LogcatUtils.e(" pos机 TransactionCompletion terminal 为空 ");
                ToastUtils.showShort(" pos机 TransactionCompletion terminal 为空");
            }

        }).start();

    }

    @Override
    public void onSucceed(JSONObject jsonData, int id, CommonalityModel commonality) throws JSONException {
        JSONObject data = jsonData.optJSONObject("data");
        switch (id) {
            case ApiUrl.baifu_deviceScan_Id:
                if (posListener != null) {
                    posListener.deviceScanSucceed(data.optString("text"));
                }
                Observable.timer(10, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(Long aLong) {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {
                        createOrder(account);
                    }
                });

                break;

            case ApiUrl.baifu_createOrder_Id:
                String order_no = data.optString("order_no");
                transactionStar(account, order_no);
                break;

            case ApiUrl.baifu_payOrderSuccess_Id:
                if (currentPayIndex < paySize) {
                    if (currentPayIndex == paySize - 1) {
                        //继续循环checkoutOrder()
                        loopCheckoutOrder = true;
                    } else {
                        currentPayIndex = currentPayIndex + 1;
                        TransactionCompletion(posOrderBean.data.get(currentPayIndex).amount, posOrderBean.data.get(currentPayIndex).order_no,
                                posOrderBean.data.get(currentPayIndex).originalHostData, posOrderBean.data.get(currentPayIndex).originalHostReferenceNumber);
                    }
                }
                break;

            case ApiUrl.baifu_freezeSuccess_Id:
                cancelCardInfo();
                if (posListener != null) {
                    posListener.paySuccess();
                }
                break;

            case ApiUrl.baifu_checkoutOrder_Id:
                paySize = 0;
                currentPayIndex = 0;
                posOrderBean = GsonUtils.parseJObject(jsonData.toString(), PosOrderBean.class);
                if (posOrderBean != null && posOrderBean.data != null) {
                    if (posOrderBean.data.size() > 0) {
                        paySize = posOrderBean.data.size();
                        LogcatUtils.e("pos机 执行最终扣款 ");
                        TransactionCompletion(posOrderBean.data.get(currentPayIndex).amount, posOrderBean.data.get(currentPayIndex).order_no,
                                posOrderBean.data.get(currentPayIndex).originalHostData, posOrderBean.data.get(currentPayIndex).originalHostReferenceNumber);


                    }
                }
                break;

        }
    }

    @Override
    public void onFail(JSONObject jsonData, int id, CommonalityModel commonality) {
        JSONObject data = jsonData.optJSONObject("data");
        ToastUtils.showShort(commonality.getMsg());
        cancelCardInfo();
        if (posListener != null) {
            posListener.freezeFail();
        }

    }

    @Override
    public void onError(int id, Exception e) {
        cancelCardInfo();
        if (posListener != null) {
            posListener.freezeFail();
        }

    }


    public interface PosListener {

        void initFail();

        //刷卡
        void readCard();

        //加载Ui
        void deviceScanSucceed(String text);

        //支付成功
        void paySuccess();

        //失败
        void freezeFail();


    }


}
